{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b89d17d2",
   "metadata": {},
   "source": [
    "# 开始使用 ZeroMQ"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "108eede3",
   "metadata": {},
   "source": [
    "ZeroMQ（也拼写为 ØMQ、0MQ 或 ZMQ）是高性能异步消息传递库，旨在用于分布式或并发应用程序。它提供了一个消息队列，但与面向消息的中间件不同，ZeroMQ 系统可以在没有专用消息代理的情况下运行。\n",
    "\n",
    "ZeroMQ 支持通过各种传输（TCP、进程内、进程间、multicast、WebSocket 等）的常见消息传递模式（发布/订阅、请求/回复、客户端/服务器等），使进程间消息传递像线程间消息传递一样简单。这使您的代码保持清晰、模块化且极其易于扩展。\n",
    "\n",
    "ZeroMQ 是由庞大的贡献者社区开发的。许多流行的编程语言都有第三方绑定，C# 和 Java 也有本机端口。\n",
    "\n",
    "```{admonition} ZeroMQ 中的零\n",
    "ZeroMQ 的理念从零开始。零表示零代理（ZeroMQ 是无代理）、零延迟、零成本（免费）和零管理。\n",
    "\n",
    "更一般地说，“零”是指渗透到项目中的极简主义文化。通过消除复杂性而不是通过公开新功能来增加功能。\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b22c6bf4",
   "metadata": {},
   "source": [
    "[指南](http://zguide.zeromq.org/page:all)解释了如何使用 ØMQ，涵盖了基础、中级和高级使用，包括 60+ 图表和 750 个示例，包括 28 种语言。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b07876d3",
   "metadata": {},
   "source": [
    "```{admonition} 用一百个字描述 ZeroMQ\n",
    "ZeroMQ（也称为ØMQ、0MQ 或 zmq）看起来像是可嵌入的网络库，但实际上是并发框架。它为您提供可以在进程内、进程间、TCP 和多播等不同传输方式上携带原子消息的套接字。您可以使用类似 fan-out、pub-sub、任务分配和请求-回复的模式将套接字 N 对 N 地连接起来。它足够快，可以成为集群产品的架构。其异步 I/O 模型让您能够构建可扩展的多核应用程序，这些应用程序作为异步消息处理任务。它拥有多种语言 API，并在大多数操作系统上运行。ZeroMQ 来自 [iMatix](http://www.imatix.com/)，是 LGPLv3 开源项目。\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48093bb8",
   "metadata": {},
   "source": [
    "## 第一个 Python 例子\n",
    "\n",
    "安装\n",
    "```bash\n",
    "pip install pyzmq\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc385bff",
   "metadata": {},
   "source": [
    "```python\n",
    "#\n",
    "#   Hello World server in Python\n",
    "#   Binds REP socket to tcp://*:5555\n",
    "#   Expects b\"Hello\" from client, replies with b\"World\"\n",
    "#\n",
    "\n",
    "import time\n",
    "import zmq\n",
    "\n",
    "context = zmq.Context()\n",
    "socket = context.socket(zmq.REP)\n",
    "socket.bind(\"tcp://*:5555\")\n",
    "\n",
    "while True:\n",
    "    #  Wait for next request from client\n",
    "    message = socket.recv()\n",
    "    print(f\"Received request: {message}\")\n",
    "\n",
    "    #  Do some 'work'\n",
    "    time.sleep(1)\n",
    "\n",
    "    #  Send reply back to client\n",
    "    socket.send(b\"World\")\n",
    "````"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30ed2018",
   "metadata": {},
   "source": [
    "服务器创建 response 类型的套接字，将其绑定到端口 5555，然后等待消息。您还可以看到配置为零，只是在发送字符串。\n",
    "\n",
    "```python\n",
    "#\n",
    "#   Hello World client in Python\n",
    "#   Connects REQ socket to tcp://localhost:5555\n",
    "#   Sends \"Hello\" to server, expects \"World\" back\n",
    "#\n",
    "\n",
    "import zmq\n",
    "\n",
    "context = zmq.Context()\n",
    "\n",
    "#  Socket to talk to server\n",
    "print(\"Connecting to hello world server…\")\n",
    "socket = context.socket(zmq.REQ)\n",
    "socket.connect(\"tcp://localhost:5555\")\n",
    "\n",
    "#  Do 10 requests, waiting each time for a response\n",
    "for request in range(10):\n",
    "    print(f\"Sending request {request} …\")\n",
    "    socket.send(b\"Hello\")\n",
    "\n",
    "    #  Get the reply.\n",
    "    message = socket.recv()\n",
    "    print(f\"Received reply {request} [ {message} ]\")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36863dfe",
   "metadata": {},
   "source": [
    "客户端创建 request 类型的套接字，连接并开始发送消息。\n",
    "\n",
    "默认情况下， 发送和接收方法都处于阻塞状态。对于接收很简单：如果没有消息，该方法将阻塞。对于发送，它更复杂，取决于 socket 类型。对于请求套接字，如果达到高水位线或未连接对等方，则该方法将阻塞。"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
